package gp;



/**
 * @author Beacom
 * @version 1.0
 * @created 18-Feb-2008 12:43:43 PM
 */
public class OperatorNode extends OrganismNode {

	public static final String ADD = "+";
	public static final String SUBTRACT = "-";
	public static final String MULTIPLY = "*";
	public static final String DIVIDE = "/";
	
	private OrganismNode leftChild;
	private OrganismNode rightChild;
	
	private String operator;	
	
	public OperatorNode(){
		operator="";
	}
	
	public OperatorNode(OperatorNode original) {
		this.operator = original.operator;
		this.leftChild = original.leftChild.createCopy();
		this.rightChild = original.rightChild.createCopy();
	}
	
	public OperatorNode createCopy() {
		return new OperatorNode(this);
	}
	
	public OperatorNode(String opr){
		operator = opr;
	}
	
	public OperatorNode mutate() {
		double randomNumber = Math.random();
		if(randomNumber < 0.10) {
			this.selectRandomOperation();
		} else if( randomNumber < 0.55) {
			leftChild.mutate();
		} else {
			rightChild.mutate();
		}
		return this;
	}
	
	public void setOperator(String opr){
		operator = opr;
	}
	
	public String getOperator(){
		return operator;
	}
	
	public OperatorNode selectRandomOperation() {
		double randomNumber = Math.random();
		if(randomNumber < 0.25) {
			operator = ADD;
		} else if(randomNumber < 0.50) {
			operator = SUBTRACT;
		} else if(randomNumber < 0.75) {
			operator = MULTIPLY;
		} else {
			operator = DIVIDE;
		}
		return this;
	}
	
	public OperatorNode generateRandomChildren(int depth, String[] variables) {
		if(depth > 0) {
			leftChild = new OperatorNode().selectRandomOperation().generateRandomChildren(depth - 1,variables);
			rightChild = new OperatorNode().selectRandomOperation().generateRandomChildren(depth - 1,variables);
		} else {
			leftChild = new OperandNode().selectRandomOperandValue(variables);
			rightChild = new OperandNode().selectRandomOperandValue(variables);
		}
		return this;
	}
	
	public void setLeftChild(OrganismNode left){
		leftChild=left;
	}
	
	public void setRightChild(OrganismNode right){
		rightChild=right;
	}
	
	public OrganismNode getLeftChild(){
		return leftChild;
	}
	
	public OrganismNode getRightChild(){
		return rightChild;
	}

	@Override
	public void finalize() throws Throwable {
		super.finalize();
	}

	@Override
	public double evaluate() throws Exception{
		double left = leftChild.evaluate();
		double right = rightChild.evaluate();
		if (operator.equals(ADD))
			return ( left + right);
		else if(operator.equals(SUBTRACT))
			return (left - right);
		else if(operator.equals(MULTIPLY))
			return (left * right);
		else if (operator.equals(DIVIDE))
			return (left / (right == 0 ? 1 : right) ); // we may need a more elegant solution
		else
			throw new Exception("Invalid operation attempted " + operator);
	}
	
	public void setVariable(String var, double val){
		if(leftChild != null) {
			leftChild.setVariable(var,val);
		}
		if(rightChild != null) {
			rightChild.setVariable(var,val);
		}
	}
	
/*	public String toString() {
		String output = " OperatorNode " + operator;
		if(leftChild != null) {
			output += leftChild;
		}
		if(rightChild != null) {
			output += rightChild;
		}
		return output;
	}*/

	public String toString() {
		String output="(";
		if (leftChild!=null){
			output+=leftChild;
		}
		output+=operator;
		if(rightChild!=null){
			output+=rightChild;
		}
		output+=")";
		return output;
	}
}